package chat_views

import (
	"encoding/json"
	"github.com/gorilla/websocket"
	"github.com/labstack/echo/v4"
	"gopkg.in/go-playground/validator.v9"
	"log"
	"net/http"
	"rabbit_love/src/service/client/daos/user_daos"
	"rabbit_love/src/service/client/utils"
	"rabbit_love/src/utils/response"
	"strconv"
	"strings"
	"time"
)

// ChatRequest 请求Request
type ChatRequest struct {
	MineId int64 `query:"mineId" validate:"required"`
	SendId int64 `query:"sendId" validate:"required"`
}

func (reg *ChatRequest) Validator() error {
	validate := validator.New()
	err := validate.Struct(reg)
	return err
}

type Client struct {
	MineId         string
	SendId         string
	Socket         *websocket.Conn
	Message        chan *Message
	ProductionTime int64
}

type Message struct {
	Msg  string `json:"msg"`
	Code int    `json:"code"`
	From int64  `json:"from"`
}

type BroadCast struct {
	Client  *Client
	Message Message
}

type ClientManager struct {
	Users     map[string]*Client
	BroadCast chan *BroadCast

	Register   chan *Client
	UnRegister chan *Client
}

type SendMsg struct {
	Type    WsType `json:"type"`
	Content string `json:"content"`
}

var Manager = &ClientManager{
	Register:   make(chan *Client, 1000),
	UnRegister: make(chan *Client, 1000),
	Users:      make(map[string]*Client),
	BroadCast:  make(chan *BroadCast, 1000),
}

func CreatedID(mineId, sendId int64) string {
	return strconv.FormatInt(mineId, 10) + "->" + strconv.FormatInt(sendId, 10)
}

func HandleChatWs(ctx echo.Context) error {
	var (
		userId  int
		loverId int
		err     error
	)
	userId = utils.GetUserId(ctx)
	loverId = utils.GetLoverId(ctx)
	if userId == 0 || loverId == 0 {
		return response.RespErr(ctx, "用户验证失败，请重新登录")
	}

	loverUserID := user_daos.GetLoverUserId(userId, loverId)

	upgrade := websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool { // CheckOrigin解决跨域问题
			return true
		}}
	conn, err := upgrade.Upgrade(ctx.Response().Writer, ctx.Request(), nil) // 升级成ws协议
	if err != nil {
		http.NotFound(ctx.Response().Writer, ctx.Request())
		return err
	}

	client := &Client{
		MineId:         CreatedID(int64(userId), loverUserID),
		SendId:         CreatedID(loverUserID, int64(userId)),
		Socket:         conn,
		Message:        make(chan *Message),
		ProductionTime: time.Now().Unix(),
	}

	Manager.Register <- client

	go client.Read()
	go client.Write()

	return nil
}

func (c *Client) Read() {
	defer func() {
		Manager.UnRegister <- c
		_ = c.Socket.Close()
	}()

	for {
		time.Sleep(time.Second)
		c.Socket.PongHandler()

		sendMsg := new(SendMsg)
		err := c.Socket.ReadJSON(&sendMsg)
		if err != nil {
			log.Println("连接断开喽", err)
			Manager.UnRegister <- c
			break
		}

		if sendMsg.Type == HeartBeatsType {
			// 心跳刷新
			c.ProductionTime = time.Now().Unix()
			_ = c.Socket.WriteMessage(websocket.TextMessage, []byte("HEARTBEATS！"))
		} else if sendMsg.Type == SendMsgType {
			// 广播信号
			fromId, _ := strconv.Atoi(strings.Split(c.MineId, "->")[0])
			Manager.BroadCast <- &BroadCast{
				Client: c,
				Message: Message{
					Msg:  sendMsg.Content,
					Code: WSSendMsg,
					From: int64(fromId),
				},
			}
		} else if sendMsg.Type == GetHistoryType {
			// 获取未读的消息
			allMsg := FindAllMsg(c.MineId)
			for _, val := range allMsg {
				marshal, err := json.Marshal(val)
				if err != nil {
					log.Println("Json Err: ", err)
				}
				_ = c.Socket.WriteMessage(websocket.TextMessage, marshal)
			}
		} else if sendMsg.Type == DisConnectType {
			Manager.UnRegister <- c
		}
	}
}

type ReplyMsg struct {
	From    int64 `json:"from"`
	Code    int   `json:"code"`
	Content interface{}
}

func (c *Client) Write() {
	defer func() {
		_ = c.Socket.Close()
	}()
	for {
		select {
		case message, ok := <-c.Message:
			if !ok {
				_ = c.Socket.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}
			log.Printf("%v 接受消息: %+v", c.MineId, message)

			marshal, err := json.Marshal(message)
			if err != nil {
				log.Println("Json Err: ", err)
			}
			_ = c.Socket.WriteMessage(websocket.TextMessage, marshal)
		}

	}
}
